#ifndef _UTILS_LOG_H_
#define _UTILS_LOG_H_

#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#include <chrono>
#include <iostream>

#define MAX_LOG_LEN (256)

#ifndef LOG_TAG
#define LOG_TAG "common"
#endif

double get_sys_secend() {
    static std::chrono::steady_clock::time_point clock_ZERO;
    static std::chrono::steady_clock::time_point cur_clock;
    static std::chrono::steady_clock::duration span;

    cur_clock = std::chrono::steady_clock::now();
    span = cur_clock - clock_ZERO;
    return double(span.count()) * std::chrono::steady_clock::period::num /
           std::chrono::steady_clock::period::den;
}

static double init_time = get_sys_secend();

void log_tag(const char *color, const char *TAG, const char *ModuleTAG,
             const char *format, ...) {
    char logstr[MAX_LOG_LEN];
    snprintf(logstr, MAX_LOG_LEN, "%s%.03lf %s %s ", color,
             get_sys_secend() - init_time, TAG, ModuleTAG);

    va_list vlArgs;
    va_start(vlArgs, format);
    vsnprintf(logstr + strlen(logstr), MAX_LOG_LEN - strlen(logstr), format,
              vlArgs);
    va_end(vlArgs);
    fprintf(stderr, "%s\n", logstr);
    return;
}

#define LOGD(...) \
    { log_tag("\033[0;36m", "D", LOG_TAG, __VA_ARGS__); }
#define LOGI(...) \
    { log_tag("\033[0;32m", "I", LOG_TAG, __VA_ARGS__); }
#define LOGW(...) \
    { log_tag("\033[0;33m", "W", LOG_TAG, __VA_ARGS__); }
#define LOGE(...) \
    { log_tag("\033[0;31m", "E", LOG_TAG, __VA_ARGS__); }

#define TRACE_B(...) \
    Trace trace;     \
    trace.begin(LOG_TAG, __func__, ##__VA_ARGS__);

class Trace {
   public:
    bool mLogOn = true;
    char mTag[48] = {0};
    double st = 0.0;  // start time
    Trace() { st = get_sys_secend(); }

    ~Trace() {
        if (mLogOn) {
            double span = get_sys_secend() - st;
            log_tag("\033[0;31m", "I", "", "[T_END] %s X. \t perf:%.2lfms",
                    mTag, span * 1000);
        }
    }

    bool begin(const char *logtagstr, const char *func_name) {
        begin(logtagstr, func_name, "");
        return true;
    }

    bool begin(const char *logtagstr, const char *func_name, const char *format,
               ...) {
        if (mLogOn) {
            va_list args;
            va_start(args, format);
            int len =
                snprintf(mTag, sizeof(mTag), "%s %s() ", logtagstr, func_name);
            vsnprintf(mTag + len, sizeof(mTag) - len, format, args);
            va_end(args);
            log_tag("\033[0;31m", "I", "", "[T_BEG] %s E", mTag);
        } else {
            return false;
        }

        return true;
    }
};

#endif  // _UTILS_LOG_H_
